package main

import (
	"time"
	"sync/atomic"
	"fmt"
)

var done chan struct{} = make(chan struct{})
var num int32

func CompareAndAdd(id, times int, increment int32) {
	defer func() {
		done <- struct{}{}
	}()
	for i := 0; i < times; i++ {
		for {
			currNum := atomic.LoadInt32(&num)  // 先获取当前的值
			newNum := currNum + increment  // 这里希望对num做加法
			// 假设是一个耗时的操作，就是有可能在这段时间里有别的goroutine已经修改了num
			time.Sleep(time.Millisecond * 300)
			// 比较现在num的值和操作前获取到的值是否一致，如果一致，表示表里没有别修改过，可以更新为新值
			// 如果不一致，表示在这段时间里num已经被别的goroutine修改过了，必须重新来过
			if atomic.CompareAndSwapInt32(&num, currNum, newNum) {
				fmt.Printf("更新num[%d-%d]: +%d = %d\n", id, i, increment, newNum)
				break
			} else {
				fmt.Printf("更新num失败[%d-%d]，重试...\n", id, i)
			}
		}
	}
}

func main() {
	go CompareAndAdd(1, 6, 2)
	go CompareAndAdd(2, 4, 3)
	go CompareAndAdd(3, 3, 4)
	<- done
	<- done
	<- done
	fmt.Println("Over")
}